package represent.type;

/**
 * The class that wraps Java ints as database constants.
 * @author Edward Sciore
 */
public class IntType implements Type {
	private Integer val;

	/**
	 * Create a constant by wrapping the specified int.
	 * @param n the int value
	 */
	public IntType(int n) {
		val = new Integer(n);
	}

	public IntType(String s) {
		val = new Integer(s);
	}

	public IntType(Type v) {
		Object jval = v.asJavaVal();
		if(v instanceof IntType)
			val = (Integer)jval;
		else if(v instanceof FloatType)
			val = ((Float) jval).intValue();
		else if(v instanceof DecimalType)
			val = ((Double)jval).intValue();
		else
			throw new Error("Cannot convert " + jval + " to float.");
	}

	/**
	 * Unwraps the Integer and returns it.
	 * @see simpledb.query.Type#asJavaVal()
	 */
	public Object asJavaVal() {
		return val;
	}

	public Type getDecFromString(String s) {
		Integer i = null;
		Double f = null;
		try {
			i = new Integer(s);
		} catch(Exception e1) {
			try {
				f = new Double(s);
			} catch(Exception e2) {
				throw new Error("Cannot convert " + s + " to number");
			}
		}
		if(i != null)
			return new IntType(i);
		else
			return new DecimalType(f);
	}

	public boolean equals(Object o) {
		if (o instanceof StringType) {
			String v = ((StringType) o).asJavaVal();
			return equals(getDecFromString(v));
		} else if (o instanceof IntType)
			return val.equals((Integer) ((IntType) o).asJavaVal());
		else if (o instanceof FloatType) {
			FloatType lhv = new FloatType(this);
			FloatType rhv = (FloatType) o;
			return lhv.equals(rhv);
		} else if (o instanceof DecimalType) {
			DecimalType lhv = new DecimalType(this);
			DecimalType rhv = (DecimalType) o;
			return lhv.equals(rhv);
		} else
			throw new Error("Inconsistent type." + o);
	}

	public int compareTo(Type c) {
		if (c instanceof StringType) {
			String v = ((StringType) c).asJavaVal();
			return compareTo(getDecFromString(v));
		} else if (c instanceof IntType)
			return val.compareTo((Integer) ((IntType) c).asJavaVal());
		else if (c instanceof FloatType) {
			FloatType lhv = new FloatType(this);
			FloatType rhv = (FloatType) c;
			return lhv.compareTo(rhv);
		} else if (c instanceof DecimalType) {
			DecimalType lhv = new DecimalType(this);
			DecimalType rhv = (DecimalType) c;
			return lhv.compareTo(rhv);
		} else
			throw new Error("Inconsistent type.");
	}

	public int hashCode() {
		return val.hashCode();
	}

	public String toString() {
		return val.toString();
	}

	public String getType() {
		return "int";
	}

	public Type plus(Type c) {
		if (c instanceof StringType) {
			String v = ((StringType) c).asJavaVal();
			return plus(getDecFromString(v));
		}
		else if (c instanceof IntType)
			return new IntType(val + (Integer) c.asJavaVal());
		else if (c instanceof FloatType) {
			FloatType lhv = new FloatType(this);
			FloatType rhv = (FloatType) c;
			return lhv.plus(rhv);
		} else if (c instanceof DecimalType) {
			DecimalType lhv = new DecimalType(this);
			DecimalType rhv = (DecimalType) c;
			return lhv.plus(rhv);
		} else
			throw new Error("Inconsistent types.");
	}


	public Type divide(Type c) {
		if (c instanceof StringType) {
			String v = ((StringType) c).asJavaVal();
			return divide(getDecFromString(v));
		}
		else if (c instanceof IntType)
			return new IntType(val / (Integer) c.asJavaVal());
		else if (c instanceof FloatType) {
			FloatType lhv = new FloatType(this);
			FloatType rhv = (FloatType) c;
			return lhv.divide(rhv);
		} else if (c instanceof DecimalType) {
			DecimalType lhv = new DecimalType(this);
			DecimalType rhv = (DecimalType) c;
			return lhv.divide(rhv);
		} else
			throw new Error("Inconsistent types.");
	}

	public Type minus(Type c) {
		if (c instanceof StringType) {
			String v = ((StringType) c).asJavaVal();
			return minus(getDecFromString(v));
		}
		else if (c instanceof IntType)
			return new IntType(val - (Integer) c.asJavaVal());
		else if (c instanceof FloatType) {
			FloatType lhv = new FloatType(this);
			FloatType rhv = (FloatType) c;
			return lhv.minus(rhv);
		} else if (c instanceof DecimalType) {
			DecimalType lhv = new DecimalType(this);
			DecimalType rhv = (DecimalType) c;
			return lhv.minus(rhv);
		} else
			throw new Error("Inconsistent types.");
	}

	public Type mod(Type c) {
		if (c instanceof StringType) {
			String v = ((StringType) c).asJavaVal();
			return mod(getDecFromString(v));
		}
		else if (!(c instanceof IntType))
			throw new Error("Inconsistent types.");
		return new IntType(val % (Integer) (c.asJavaVal()));
	}

	public Type mult(Type c) {
		if (c instanceof StringType) {
			String v = ((StringType) c).asJavaVal();
			return mult(getDecFromString(v));
		}
		else if (c instanceof IntType)
			return new IntType(val * (Integer) c.asJavaVal());
		else if (c instanceof FloatType) {
			FloatType lhv = new FloatType(this);
			FloatType rhv = (FloatType) c;
			return lhv.mult(rhv);
		} else if (c instanceof DecimalType) {
			DecimalType lhv = new DecimalType(this);
			DecimalType rhv = (DecimalType) c;
			return lhv.mult(rhv);
		} else
			throw new Error("Inconsistent types.");
	}

	public static int compare(byte[] a, byte[] b) {
		// TODO �Զ���ɷ������
		return 0;
	}

	public static IntType fromBytes(byte[] bytes) {
		// TODO �Զ���ɷ������
		return null;
	}

	public int TypeToInt() {
		return utils.Constant.INT;
	}
	
	public static int length() {
		return 4;
	}
	
}
